All files / src/components/user ModernUserSidebar.tsx

0% Statements 0/28
0% Branches 0/11
0% Functions 0/5
0% Lines 0/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178                                                                                                                                                                                                                                                                                                                                                                   
'use client';
/* eslint-disable @typescript-eslint/no-unused-vars */
 
import Link from 'next/link';
import { useMemo, memo } from 'react';
import { usePathname } from 'next/navigation';
import { useTranslation } from 'react-i18next';
 
import LogoutButton from '@/components/auth/LogoutButton';
import { useAuth } from '@/contexts/AuthContext';
import { ROUTES, APP_NAME } from '@/constants/app';
import { cn } from '@/lib/utils';
 
import {
  Home,
  Search,
  MonitorSmartphone,
  User,
  LucideIcon} from 'lucide-react';
 
import { CATEGORY_ICONS } from '@/constants/categoryIcons';
 
interface MenuItem {
  label: string;
  href: string;
  icon: LucideIcon;
  basePath: string;
}
 
const ModernUserSidebar = memo(function ModernUserSidebar() {
  const { t } = useTranslation();
  const { user } = useAuth();
  const pathname = usePathname();
 
  const usernameLabel = useMemo(
    () => user?.username || t('user.dashboard.guest'),
    [t, user?.username],
  );
 
  const menuItems = useMemo(() => {
    const items: MenuItem[] = [
      {
        label: t('user.menu.home'),
        href: ROUTES.USER.DASHBOARD,
        icon: Home,
        basePath: ROUTES.USER.DASHBOARD},
      {
        label: t('user.menu.search'),
        href: ROUTES.USER.SEARCH,
        icon: Search,
        basePath: ROUTES.USER.SEARCH},
      {
        label: t('user.menu.liveTv'),
        href: ROUTES.USER.LIVE,
        icon: CATEGORY_ICONS.LiveTV,
        basePath: ROUTES.USER.LIVE},
      {
        label: t('user.menu.movies'),
        href: ROUTES.USER.MOVIES,
        icon: CATEGORY_ICONS.Movies,
        basePath: ROUTES.USER.MOVIES},
      {
        label: t('user.menu.series'),
        href: ROUTES.USER.SHOWS,
        icon: CATEGORY_ICONS.Series,
        basePath: ROUTES.USER.SHOWS},
      {
        label: t('user.menu.kids'),
        href: ROUTES.USER.KIDS,
        icon: CATEGORY_ICONS.Kids,
        basePath: ROUTES.USER.KIDS},
      {
        label: t('user.menu.anime'),
        href: ROUTES.USER.ANIME,
        icon: CATEGORY_ICONS.Anime,
        basePath: ROUTES.USER.ANIME},
      {
        label: t('user.menu.events'),
        href: ROUTES.USER.EVENTS,
        icon: CATEGORY_ICONS.Events,
        basePath: ROUTES.USER.EVENTS},
      {
        label: t('user.menu.favorites'),
        href: ROUTES.USER.FAVORITES,
        icon: CATEGORY_ICONS.Favorites,
        basePath: ROUTES.USER.FAVORITES},
    ];
 
    return items;
  }, [t]);
 
  const isItemActive = (basePath: string) => {
    if (basePath === ROUTES.USER.DASHBOARD) {
      return pathname === basePath;
    }
    return pathname === basePath || pathname.startsWith(`${basePath}/`);
  };
 
  return (
    <aside className="hidden md:flex h-screen shrink-0 flex-col w-72 fixed left-0 top-0 z-50 bg-[#050505]/95 backdrop-blur-2xl border-r border-white/5 shadow-2xl">
      {/* Brand / Header */}
      <div className="px-7 pt-9 pb-8 flex items-center justify-between">
        <h1 className="text-2xl font-bold text-white tracking-wider">
          {APP_NAME}
        </h1>
      </div>
 
      {/* Main Navigation */}
      <nav className="flex-1 px-5 space-y-3 overflow-y-auto scrollbar-thin pb-6">
        {menuItems.map((item) => {
          const Icon = item.icon;
          const active = isItemActive(item.basePath);
 
          return (
            <Link
              key={item.href}
              href={item.href}
              className={cn(
                'group flex items-center space-x-4 rounded-xl px-4 py-3.5 transition-all duration-200 ease-in-out outline-none focus-visible:ring-2 focus-visible:ring-blue-500',
                active
                  ? 'bg-blue-600/10 text-blue-400 font-semibold shadow-[0_0_15px_rgba(37,99,235,0.15)] border border-blue-600/10'
                  : 'text-slate-400 hover:text-white hover:bg-white/5 border border-transparent'
              )}
            >
              <Icon className={cn("h-5 w-5 shrink-0 transition-transform duration-200 group-hover:scale-110", active ? "text-blue-400" : "group-hover:text-white")} />
              <span className="text-sm font-medium truncate">{item.label}</span>
 
              {active && (
                <div className="ml-auto w-1.5 h-1.5 rounded-full bg-blue-500 shadow-[0_0_8px_#3b82f6]" />
              )}
            </Link>
          );
        })}
      </nav>
 
      {/* User / Footer Section */}
      <div className="p-5 mt-auto border-t border-white/5 bg-black/40 backdrop-blur-sm">
        <div className="flex items-center gap-3.5 mb-5 px-1">
          <div className="w-10 h-10 rounded-full bg-gradient-to-br from-blue-600 to-violet-600 flex items-center justify-center text-sm font-bold text-white shadow-lg ring-2 ring-black/50">
            {usernameLabel.charAt(0).toUpperCase()}
          </div>
          <div className="flex-1 overflow-hidden">
            <p className="text-sm font-semibold text-white truncate leading-tight">{usernameLabel}</p>
            <div className="flex items-center gap-1.5 mt-1">
              <span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" />
              <span className="text-[10px] text-emerald-400 font-medium tracking-wide">{t('layout.online')}</span>
            </div>
          </div>
        </div>
 
        <div className="grid grid-cols-2 gap-3 mb-4">
          <Link
            href={ROUTES.USER.PROFILE}
            className="flex flex-row items-center justify-center gap-2 p-3 rounded-xl bg-white/5 hover:bg-white/10 text-slate-400 hover:text-white transition-all duration-200 border border-white/5 hover:border-white/10 hover:-translate-y-0.5"
          >
            <User className="h-4 w-4" />
            <span className="text-xs font-medium">{t('user.dashboard.profile')}</span>
          </Link>
          <Link
            href={ROUTES.USER.DEVICES}
            className="flex flex-row items-center justify-center gap-2 p-3 rounded-xl bg-white/5 hover:bg-white/10 text-slate-400 hover:text-white transition-all duration-200 border border-white/5 hover:border-white/10 hover:-translate-y-0.5"
          >
            <MonitorSmartphone className="h-4 w-4" />
            <span className="text-xs font-medium">{t('user.dashboard.manageDevices')}</span>
          </Link>
        </div>
 
        <LogoutButton
          variant="ghost"
          className="w-full justify-start pl-2 text-slate-400 hover:text-red-400 hover:bg-red-500/10 transition-colors h-10 text-sm font-medium"
        />
      </div>
    </aside>
  );
});
 
export default ModernUserSidebar;